/*

   MCL STRING - A component library of the Sigh misc. C library.

   Copyright (c) 2011, Sulaiman A. Mustafa

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
   
   ________________________________________________________________________
   
   Note:
      The functions contained herein are documented mcl_str.h 
      
   ________________________________________________________________________
   
   Implementation notes:
   
        buffer = [ SIZE OF STR | ERR |       STR             | NUL ]

   0- function pseodo process:
      
      >> if string is an mcl string, it is shifted back four bytes.
      >> now string points to integer and string content is 4 bytes ahead.
      >> before returning, the function shifts the pointer 4 bytes ahead.
      
   
   1- The first four bytes of a mcl_str string contain the length of the string
   and not the length of the buffer itself! (in other words, the null character
   and the bytes taken at the begaining of the string for int are not counted.)
   
   2- The library always returns and takes mcl strings from the actual string 
   starting point and not the bigening of the buffer itself. This way the user
   can work with the string normally but can not free the string himself.
   
   3- There are three ways to handle a prepared mcl string:
      A- as buffer ptr: This is what you use to resize the buffer and what not.
      B- as a char* ptr:   (using mcl_str__straddr) this is what you use when 
                           handling it as a string (strcpy, return)
      C- as a int* ptr for string length (using mcl_str__lenaddr).
      
   4- The process by which a mcl string is updated is the following:
      A- The buffer is resized.
      B- The string is modefied.
      C- The length is updated.
      
   5- mcl string functions always return pointers to the str portion of the 
      string and not to the buffer.

*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>


#define MCL_STR_CORE_C
#include "mcl/str.h"

mcl_str_t*    mcl_str(const char* string){
   char *buffer=NULL;
   int length;

   if (!string){  /* if NULL was provided */
	   string="";		
   }
   length=strlen(string);
   buffer=mcl_str___sct(buffer, string, length);
   mcl_str__checkmemalloc(buffer, "mcl_str");
   *mcl_str__erraddr(buffer)=MCL_STR_OK;
   
   return mcl_str__straddr(buffer);
}

mcl_str_t*    mcl_str_cz(mcl_str_t *string){ 
   mcl_str_t *buffer;

   buffer=NULL; 
   mcl_str__prepare(string);
   buffer=mcl_str___sct(buffer, mcl_str__straddr(string), *mcl_str__lenaddr(string));
   mcl_str__checkmemalloc(buffer, "mcl_str_cz");
   *mcl_str__erraddr(buffer)=MCL_STR_OK;
   
   return mcl_str__straddr(buffer);
}

int   mcl_str_len(mcl_str_t *string){
   mcl_str__prepare(string);
   return *(mcl_str__lenaddr(string));
}


mcl_str_t*    mcl_str_free(mcl_str_t *string){
   //TODO: check if ENOMEM error string was passed which should be ignored
   if(string){
      mcl_str__prepare(string);
      free(string);
   }
   return NULL;
}





mcl_str_t* mcl_str___stretch(mcl_str_t* buf, int size){
	if(!(buf=(char *)realloc(buf, sizeof(char)*(size+MCL_STR_EXTRA_BYTES)))){
		return NULL;
	}
	return buf;
}

mcl_str_t* mcl_str___sct(mcl_str_t* DEST, const char *SRC, int LEN){
   DEST=mcl_str___stretch(DEST, LEN);
	if(!DEST){
	   return NULL;
	}
	strncpy(mcl_str__straddr(DEST), SRC, LEN);
	*mcl_str__lenaddr(DEST)=LEN;
	mcl_str__terminate(DEST);
	return DEST;
}
